#include "cmdchat.h"
#include "commmsg.h"
#include "commerrno.h"
#include "../cmd/dataprepare.h"
#include "../clan/CClanMgr.h"
#include "../cmd/cmdapi.h"

CT_REGISTER_ASYNCCMD(ID_MAIN_CHAT , CCmdChat);

int CCmdChat::Do(void* pData)
{
    CT_ASSERT(pData);

    //解析消息
    CCmdPBDoParam* pstParam = (CCmdPBDoParam*) pData;
    pstMainCtrl = (CMainCtrl*) pstParam->m_pMain;

    if (pstParam->m_pstMsgHead->msgid() != ID_MAIN_CHAT ||
        pstParam->m_pstMsgHead->msgtype() != CSMsgDef::EMT_REQUEST)
    {
        CT_ERROR(("Cmd Stat Err Cmd=%d CmdID=%d Type=%d",
            ID_MAIN_CHAT,
            pstParam->m_pstMsgHead->msgid(),
            pstParam->m_pstMsgHead->msgtype()));
        return Done(RET_SYS_ERROR);
    }

    stMsgHead = *(pstParam->m_pstMsgHead);
    stEnpHead = *(pstParam->m_pstEnpHead);
    int iRet = pstMainCtrl->DecodePBMsg(stReq, pstParam);
    if (iRet)
    {
        return AnsClients(iRet);
    }
    //消息解析结束

    uiGID = (unsigned int)stReq.gid();

    //检查登录
    iRet = pstMainCtrl->CheckLogin(uiGID, stEnpHead);
    if (iRet != RET_OK)
    {
        return AnsClients(iRet);
    }

    bHasCheckMsg = false;
    LogicDo(RET_OK);
    return RET_OK;
}

int CCmdChat::LogicDo(int iRet)
{
    if (iRet != 0)
    {
        return AnsClients(iRet);
    }

    PREPARE_PLAYER_BASE_INFO(this, uiGID);
    PREPARE_PLAYER_DETAIL_INFO(this, uiGID);
    PREPARE_PLAYER_SNS_DETAIL_INFO(this, uiGID);
    PREPARE_PLAYER_ONLINE_DATA(this, uiGID);

    int iIndex = 0;
    iIndex = pstMainCtrl->m_stPlayerBaseInfoHash.HashFind(uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("no user %u", uiGID));
        return AnsClients(RET_NO_USER);
    }
    CPlayerBaseInfo& stPlayerBaseInfo = pstMainCtrl->m_stPlayerBaseInfoHash[iIndex];

    if (stPlayerBaseInfo._ucIsInited != 1)
    {
        return AnsClients(ERROR_NOT_INITED);
    }

    if (pstMainCtrl->m_iNow < stPlayerBaseInfo._stFreezeData._iSpeakLimit)
    {
        return AnsClients(ERROR_CHAT_LIMIT);
    }

    iIndex = pstMainCtrl->m_stPlayerDetailInfoHash.HashFind(uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("no user %u", uiGID));
        return AnsClients(RET_NO_USER);
    }
    CPlayerDetailInfo& stPlayerDetailInfo = pstMainCtrl->m_stPlayerDetailInfoHash[iIndex];

    iIndex = pstMainCtrl->m_stPlayerSnsDetailInfoHash.HashFind(uiGID);
    if (iIndex < 0)
    {
        return AnsClients(RET_SYS_ERROR);
    }
    CPlayerSnsDetailInfo& stPlayerSnsDetailInfo = pstMainCtrl->m_stPlayerSnsDetailInfoHash[iIndex];

    iIndex = pstMainCtrl->m_stPlayerOnlineDataHash.HashFind(uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("no user %u", uiGID));
        return AnsClients(RET_NO_USER);
    }
    CPlayerOnlineData& stPlayerOnlineData = pstMainCtrl->m_stPlayerOnlineDataHash[iIndex];

    //检查系统是否开启
    if (!pstMainCtrl->m_stCommConfigLoader.IsOpen(SYS_OPEN_COND_ID_4, stPlayerBaseInfo, stPlayerOnlineData))
    {
        return AnsClients(ERROR_SYS_NOT_OPEN);
    }

    if ((pstMainCtrl->m_iNow - stPlayerOnlineData._iLastSendWorldMsgTime) < MAX_CHAT_SPEED)
    {
        return AnsClients(ERROR_CHAT_TOO_QUICK);
    }

    if (stReq.msg_type() == CHAT_TYPE_PRIVATE) //私聊
    {
        PREPARE_PLAYER_SNS_DETAIL_INFO(this, stReq.dest_gid());
        iIndex = pstMainCtrl->m_stPlayerSnsDetailInfoHash.HashFind(stReq.dest_gid());
        if (iIndex < 0)
        {
            return AnsClients(RET_SYS_ERROR);
        }
        CPlayerSnsDetailInfo& stDestPlayerSnsDetailInfo = pstMainCtrl->m_stPlayerSnsDetailInfoHash[iIndex];

        //检查黑名单
        if (stPlayerSnsDetailInfo._stMyInfo._stFriendData.IsInBlack(stReq.dest_gid())
            || stDestPlayerSnsDetailInfo._stMyInfo._stFriendData.IsInBlack(uiGID))
        {
            return AnsClients(ERROR_FRIEND_IN_BLACK);
        }

        //检查对方是否在线
        if (!pstMainCtrl->m_stPlayerOnline.CheckOnline(stReq.dest_gid()))
        {
            return AnsClients(ERROR_CHAT_DEST_NOT_ONLINE);
        }
    }

    //检查消息
    CTSizeString<200> szMsg;
    szMsg.Set("%s", stReq.msg().c_str());

    if (m_pstChild && ID_MAINAPI_TAPI == m_pstChild->GetCmdID())
    {
        CCmdApi* pstCmd = (CCmdApi*)m_pstChild;
        if (pstCmd->stReq._szTApiName == "/v3/csec/word_filter")
        {
            if (atoi(pstCmd->stAns._stTApiKeyValue.GetValue("is_dirty")) != 0)
            {
                if (strcmp("文本中有敏感词", pstCmd->stAns._stTApiKeyValue.GetValue("msg")) == 0)
                {
                    return AnsClients(ERROR_HAS_SEN_WORD);
                }
                else
                {
                    szMsg.Set("%s", pstCmd->stAns._stTApiKeyValue.GetValue("msg"));
                }
                
            }
        }
    }

    if (!bHasCheckMsg)
    {
        bHasCheckMsg = true;

        //检查长度，处理屏蔽字
        iRet = CheckMsg(szMsg(), szMsg.GetDataLen());
        if (iRet != RET_OK)
        {
            return AnsClients(iRet);
        }

        if (szMsg.GetDataLen() != 0 && stPlayerOnlineData._bIsTencentLogin)
        {
            //在平台检查
            CCmdApi* pstCmd = (CCmdApi*)CT_CMDFACTORY->CreateCmd(ID_MAINAPI_TAPI);
            if (!pstCmd)
            {
                CT_WARNING(("create cmd error"));
                return AnsClients(RET_SYS_ERROR);
            }

            pstCmd->pstMainCtrl = CMainCtrl::m_pstMain;
            pstCmd->stReq._ucReqType = CReqApi::API_TENCENT;
            pstCmd->stReq._szTApiName.Set("/v3/csec/word_filter");
            pstCmd->stReq._stTApiKeyValue = stPlayerOnlineData._stTencentApiKeyValue;
            pstCmd->stReq._stTApiKeyValue.SetValue("content", szMsg());

            uint64 u64MsgID = CT_UINT64_MAKE(uiGID, pstMainCtrl->m_iNow);
            pstCmd->stReq._stTApiKeyValue.SetValue("msgid", CTStringUtils::Uint64ToString(u64MsgID,16));

            RegisterChild(pstCmd, true);
            return pstCmd->Do(NULL); 
        }
    }

    if (stReq.msg_type() == CHAT_TYPE_WORLD) //公共聊天
    {
        //判断是否广告
        if (pstMainCtrl->m_stChatMgr.IsAdMsg(uiGID, szMsg))
        {
            return AnsClients(ERROR_CHAT_LIMIT);
        }
    }

    if (stReq.msg_type() == CHAT_TYPE_HORN)
    {
        //todo : 检查并扣除喇叭
    }

    //获取返回消息体
    stAns.set_gid(uiGID);
    stAns.set_name(stPlayerBaseInfo._sRoleName());
    stAns.set_is_male(stPlayerBaseInfo._ucIsMale);
    stAns.set_map_id(stPlayerOnlineData._uiNowMapID);
    stAns.set_level(stPlayerBaseInfo._shLevel);

    stAns.set_msg_type(stReq.msg_type());
    stAns.set_msg(szMsg());

    stAns.set_item_type(stReq.item_type());
    stAns.set_item_id(stReq.item_id());
    stAns.set_item_config_id(stReq.item_config_id());
    unsigned char ucItemType = stReq.item_type();
    ::google::protobuf::RepeatedField<int64> stReqIDList;

    switch(ucItemType)
    {
    case ITEM_TYPE_EQUIP:
        {
            MsgAnsItemDetailInfos* pstMsgAnsItemDetailInfos = stAns.mutable_detail();
            stReqIDList.Add(stReq.item_id());
            pstMainCtrl->m_stEquipMgr.GetEquipDetailInfo(stPlayerOnlineData, stReqIDList, *pstMsgAnsItemDetailInfos);
        }
        break;
    case ITEM_TYPE_CARD:
        {
            MsgAnsItemDetailInfos* pstMsgAnsItemDetailInfos = stAns.mutable_detail();
            stReqIDList.Add(stReq.item_id());
            pstMainCtrl->m_stCardMgr.GetCardDetailInfo(stPlayerOnlineData._stUserCard, stPlayerDetailInfo, stReqIDList, *pstMsgAnsItemDetailInfos);
        }
        break;
    case ITEM_TYPE_SCROLL:
        {
            MsgAnsItemDetailInfos* pstMsgAnsItemDetailInfos = stAns.mutable_detail();
            pstMainCtrl->m_stStorageMgr.GetScrollDetailInfo(stPlayerOnlineData, (unsigned short)stReq.item_config_id(), *(pstMsgAnsItemDetailInfos->mutable_scroll_info()));
        }
        break;
    case ITEM_TYPE_TREASURE:
        {
            MsgAnsItemDetailInfos* pstMsgAnsItemDetailInfos = stAns.mutable_detail();
            pstMainCtrl->m_stTreasureMgr.GetDetailTreasureInfo(stPlayerDetailInfo, (short)stReq.item_config_id(), *pstMsgAnsItemDetailInfos);
        }
        break;
    case ITEM_TYPE_GIFT:
        {
            //检查物品
            if (pstMainCtrl->m_stStorageMgr.GetItemCount(stPlayerOnlineData._stUserStorage, ITEM_TYPE_GIFT, stReq.item_config_id()) <= 0)
            {
                return AnsClients(RET_SYS_ERROR);
            }
        }
        break;
    default:
        break;
    }

    //获取通知目标列表
    CTArray<unsigned int, MAX_PLAYER_ONLINE> astGIDArray;
    switch(stReq.msg_type())
    {
    case CHAT_TYPE_SYSTEM:
        return AnsClients(ERROR_CHAT_CAN_NOT_SEND);
    case CHAT_TYPE_WORLD:
    case CHAT_TYPE_HORN:
        {
            pstMainCtrl->m_stChatMgr.AddMsg(uiGID, szMsg);
            pstMainCtrl->m_stPlayerOnline.GetAllOnlineUser(astGIDArray);
        }
        break;
    case CHAT_TYPE_MAP:
        {
            stPlayerOnlineData._iLastSendWorldMsgTime = pstMainCtrl->m_iNow;
            pstMainCtrl->m_stMapViews.GetMapUsers(stPlayerOnlineData._uiNowMapID, uiGID, astGIDArray);
        }
        break;
    case CHAT_TYPE_PRIVATE:
        {
            //todo: 增加离线消息
            astGIDArray.AddOneItem(stReq.dest_gid());

            //添加到最近联系列表
            iIndex = pstMainCtrl->m_stPlayerSnsDetailInfoHash.HashFind(stReq.dest_gid());
            if (iIndex < 0)
            {
                return AnsClients(RET_SYS_ERROR);
            }
            CPlayerSnsDetailInfo& stDestPlayerSnsDetailInfo = pstMainCtrl->m_stPlayerSnsDetailInfoHash[iIndex];
            
            stPlayerSnsDetailInfo._stMyInfo._stFriendData.AddRecentFriend(stReq.dest_gid());
            stDestPlayerSnsDetailInfo._stMyInfo._stFriendData.AddRecentFriend(uiGID);

            CVarObjectKey stKey;
            stKey.m_chDataType = DT_PLAYER_SNS_DETAIL_INFO;
            stKey.m_u64ID = stPlayerSnsDetailInfo._uiGID;
            pstMainCtrl->UpdateData(stKey, stPlayerSnsDetailInfo, VOP_UPDATE);

            stKey.m_chDataType = DT_PLAYER_SNS_DETAIL_INFO;
            stKey.m_u64ID = stDestPlayerSnsDetailInfo._uiGID;
            pstMainCtrl->UpdateData(stKey, stDestPlayerSnsDetailInfo, VOP_UPDATE);
        }
        break;
    case CHAT_TYPE_CLAN:
        {
            CClanEntry stClanEntry;
            iRet = pstMainCtrl->m_pstMain->m_stClanMgr.GetClanEntry(stPlayerDetailInfo._stUserClan._uiClanId, stClanEntry);
            if (iRet)
            {
                return AnsClients(iRet);
            }

            for (int i = 0; i < stClanEntry._astClanMember.Size(); ++i)
            {
                unsigned int uiClanMemGID = stClanEntry._astClanMember[i]._uiGid;
                if (!pstMainCtrl->m_stPlayerOnline.CheckOnline(uiClanMemGID))
                {
                    continue;
                }

                astGIDArray.AddOneItem(uiClanMemGID);
            }
        }
        break;
    default:
        break;
    }

    stPlayerOnlineData._iLastSendWorldMsgTime = pstMainCtrl->m_iNow;

    //发送消息
    stMsgHead.set_msgret(iRet);
    stMsgHead.set_msgtype(CSMsgDef::EMT_ANSWER);
    pstMainCtrl->m_stEncodeBuf.Clear();
    pstMainCtrl->m_stEncodeBuf.Clear();
    pstMainCtrl->EncodePBMsg(stMsgHead, pstMainCtrl->m_stEncodeBuf);
    pstMainCtrl->EncodePBMsg(stAns, pstMainCtrl->m_stEncodeBuf);

    for (int i = 0; i < astGIDArray.Size(); ++i)
    {
        if (astGIDArray[i] == uiGID)
        {
            continue;
        }
        pstMainCtrl->NotifyOnlineUser(astGIDArray[i], pstMainCtrl->m_stEncodeBuf);
    }

    return AnsClients(RET_OK);
}

int CCmdChat::AnsClients(int iRet)
{
    stMsgHead.set_msgret(iRet);
    stMsgHead.set_msgtype(CSMsgDef::EMT_ANSWER);

    if (iRet != RET_OK)
    {
        pstMainCtrl->ReturnMsgHead(stMsgHead, stEnpHead);
        return Done(iRet);
    }

    pstMainCtrl->m_stEncodeBuf.Clear();
    pstMainCtrl->EncodePBMsg(stMsgHead, pstMainCtrl->m_stEncodeBuf);
    pstMainCtrl->EncodePBMsg(stAns, pstMainCtrl->m_stEncodeBuf);
    pstMainCtrl->AnswerToClient(stEnpHead, pstMainCtrl->m_stEncodeBuf, true);
    
    return Done(iRet);
}

int CCmdChat::CheckMsg(char* sMsg, int iMsgLen)
{
    int iRet = 0;

    if (iMsgLen == 0)
    {
        return 0;
    }

    //检查字符集编码方式
    const char * sNowCharSet = pstMainCtrl->m_stCharSetConvertMgr.GetCharset(sMsg, iMsgLen, iRet);
    if (sNowCharSet == NULL || iRet != 0)
    {
        CT_WARNING(("ret = %d, char set %s", iRet, (sNowCharSet == NULL ? "NULL" : sNowCharSet)));
        return ERROR_CHAR_MSG_ERROR;
    }

    if (strncmp("UTF-8", sNowCharSet, sizeof("UTF-8")) != 0
        && strlen(sNowCharSet) != 0)
    {
        CT_WARNING(("char set %s", sNowCharSet));
        return ERROR_CHAR_MSG_ERROR;
    }

    //检查长度
    int iNameLen = CTStringUtils::GetUtf8StrLen(sMsg);
    if (iNameLen <= 0 || iNameLen > MAX_CHAT_MSG_LEN)
    {
        return ERROR_CHAR_MSG_ERROR;
    }

    //pstMainCtrl->m_stSenWordMgr.replaceSenWord(sMsg);
    
    return 0;
}





